package common.logger;

import java.io.PrintStream;
import java.util.Date;

/**
 * An abstract logger that can log at different levels and and ignore logs below a required threshold
 * 
 * @author Gal Lalouche
 */
public abstract class Logger {
	private LogLevel	level;
	
	/**
	 * @return The stream to write the logs to
	 */
	protected abstract PrintStream getStream();
	
	/**
	 * Represents a logging event importance
	 * 
	 * @author Gal Lalouche
	 */
	public enum LogLevel {
		/**
		 * The thing that should not be, is
		 */
		ASSERT,
		/**
		 * An error occurred
		 */
		ERROR,
		/**
		 * Something bad has happened
		 */
		WARNING,
		/**
		 * For your information
		 */
		INFO,
		/**
		 * General debugging messages
		 */
		DEBUG,
		/**
		 * Nonsense and drivel
		 */
		VERBOSE;
		
		boolean isLessThan(LogLevel other) {
			return ordinal() > other.ordinal();
		}
		
		@Override
		public String toString() {
			switch (this) {
			case ASSERT:
				printTrace();
				return "-*-!-*-ASSERTION-*-!-*-";
			case ERROR:
				return "-!-ERROR-!-";
			case WARNING:
				return "!WARNING!";
			case INFO:
				return "-info-";
			case DEBUG:
				return "-d";
			case VERBOSE:
				return "";
			default:
				throw new AssertionError();
			}
		}
		
		// prints the stack trace from the caller of the log
		private static void printTrace() {
			StackTraceElement[] trace = Thread.currentThread().getStackTrace();
			
			System.err.println("Assertion log in: ");
			for (int i = 6; i < trace.length; i++) {
				System.err.println(trace[i]);
			}
		}
	}
	
	/**
	 * Sets the log level for the logger; logging events below this level will be ignored
	 * 
	 * @param level The level to set
	 */
	public void setLogLevel(LogLevel level) {
		if (level == null) {
			throw new IllegalArgumentException("level is null");
		}
		
		this.level = level;
	}
	
	/**
	 * Log a new event
	 * 
	 * @param log The level of the event
	 * @param what What to log
	 */
	public void log(LogLevel log, String what) {
		if (log.isLessThan(level)) {
			return;
		}
		
		getStream().println(log + " @ " + new Date() + " - " + what);
	}
}
